/*
 *  Copyright 2010 Mahbub Mozadded Sowrov.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package com.sowrov.afrigis.tools.app.timesheet_manager;

import com.sowrov.gui.window.NotificationWindow;
import com.toedter.calendar.JDateChooser;
import com.toedter.calendar.JSpinnerDateEditor;
import java.awt.AWTException;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.io.IOException;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jdesktop.application.Action;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.TaskMonitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowListener;
import java.text.DecimalFormat;
import java.util.Date;
import javax.swing.AbstractAction;
import javax.swing.Timer;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.table.TableCellRenderer;
import com.sowrov.afrigis.tools.timesheet.PostData;
import com.sowrov.afrigis.tools.timesheet.PostDataList;
import com.sowrov.afrigis.tools.timesheet.Project;
import com.sowrov.afrigis.tools.timesheet.TimeSheetClient;
import com.sowrov.afrigis.tools.timesheet.User;
import com.sowrov.gui.model.tablemodel.CustomTableModel;
import com.sowrov.gui.renderer.ToolTipComboBoxRendered;
import com.sowrov.gui.swing.VerticalButton;
import com.sowrov.afrigis.tools.sqlite.DatabaseManager;
import com.sowrov.afrigis.tools.timesheet.parse.html.ParseSubmitPage;
import com.sowrov.gui.swing.ScrollablePanel;
import com.sowrov.gui.window.LoadingWindow;
import com.sowrov.util.formatter.TimeFormatter;
import com.sowrov.util.logsystem.ChronicleLogger;
import com.toedter.calendar.JCalendar;
import java.awt.GridLayout;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.Window;
import java.awt.event.MouseMotionListener;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Random;
import java.util.TimerTask;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.table.TableColumnModel;
import org.xml.sax.SAXException;

/**
 * TaskManagerView, The application's main frame.
 *
 * @author Sowrov
 */
public class TaskManagerView extends FrameView implements WindowListener {

    /** .*/
    private JDateChooser dateChooser;
    private JSpinnerDateEditor dateSpinner;
    private String dbFileName = "timesheet.db";
    /** .*/
    private User user;
    /** .*/
    private PostDataList currentDatePostList;
    private PostDataList toBeSubmittedPostList;
    /** .*/
    //private int macroCount = 6;
    PostDataList macroData;
    private ArrayList<VerticalButton> macroButtons;
    VerticalButton macroAdder;
    /** .*/
    private CustomTableModel activityTableModel;
    /** .*/
    private TimeSheetClient timeSheetClient;
    /** .*/
    private org.jdesktop.application.ResourceMap resourceMap;
    /** .*/
    private TrayIcon trayIcon;
    /** .*/
    private SingleFrameApplication parent;
    /** .*/
    private NotificationWindow notificationWindow;
    /** .*/
    private JTable activityTable;
    private DatabaseManager dbManager;
    private SettingWindow settingWindow;
    private boolean minimizeFirstTime;
    private boolean projectListSynchOnce;
    private LoadingWindow loadingWindow;
    private Timer notificationTimer;
    private java.util.Timer dataSubmissionTimer;
    private double totalHour;
    private String globalDateFormat = "dd/MM/yyyy";
    private int mouseActivityDetect = 1;
    private TimeFormatter timeFormatter;
    private Date currentDate;
    private Random randomIndex = new Random(System.currentTimeMillis());
    private int singleDaySynchronizationSkip;
    private JPopupMenu tableMenu;
//    private JScrollPane sideBarScrollPanel = null;
    private ScrollablePanel scrollablePanel = null;
    org.jdesktop.application.ResourceMap appResourceMap =
            org.jdesktop.application.Application.getInstance().getContext().getResourceMap(TaskManagerApp.class);

    /**
     * .
     * @param app main window
     */
    @SuppressWarnings("LeakingThisInConstructor")
    public TaskManagerView(final SingleFrameApplication app) {
        super(app);
        TaskManagerApp.splashScreen.setStatus("Starting...", 2);
        this.parent = app;
        this.resourceMap = org.jdesktop.application.Application.getInstance(
                com.sowrov.afrigis.tools.app.timesheet_manager.TaskManagerApp.class).getContext().getResourceMap(
                TaskManagerView.class);
//        Thread.sleep(2000);
        this.minimizeFirstTime = false;
        this.projectListSynchOnce = false;
        this.loadingWindow = null;
        this.timeFormatter = new TimeFormatter();
        initComponents();
        TaskManagerApp.splashScreen.setStatus("Initialize basic components", 10);

        //-----------------------------
        this.initTimesheetComponents();
        this.initMouseListener();
        //-------------------------------
        // status bar initialization - message timeout, idle icon and busy animation, etc
        this.statusMessageLabel.setForeground(Color.red);
        int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
        messageTimer = new Timer(
                messageTimeout,
                new ActionListener() {

                    public void actionPerformed(final ActionEvent e) {
                        statusMessageLabel.setText("");
                    } // end actionPerformed()
                } // end new
                );
        messageTimer.setRepeats(false);

        idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
        statusAnimationLabel.setIcon(idleIcon);
        progressBar.setVisible(false);

        TaskManagerApp.splashScreen.setStatus("Loading components...", 75);

        int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");
        int percentage = 75;
        for (int i = 0; i < busyIcons.length; i++) {
            busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");
            TaskManagerApp.splashScreen.setStatus("Loading components...", ++percentage);//90
        } // end for

        busyIconTimer = new Timer(
                busyAnimationRate,
                new ActionListener() {

                    public void actionPerformed(final ActionEvent e) {
                        busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
                        statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
                    } // end actionPerformed()
                } // end new
                );

        // connecting action tasks to status bar via TaskMonitor
        TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
        TaskManagerApp.splashScreen.setStatus("Loading components...", 95);
        taskMonitor.addPropertyChangeListener(
                new java.beans.PropertyChangeListener() {

                    public void propertyChange(final java.beans.PropertyChangeEvent evt) {
                        String propertyName = evt.getPropertyName();

                        if ("started".equals(propertyName)) {
                            if (!busyIconTimer.isRunning()) {
                                statusAnimationLabel.setIcon(busyIcons[0]);
                                busyIconIndex = 0;
                                busyIconTimer.start();
                            } // end if

                            progressBar.setVisible(true);
                            progressBar.setIndeterminate(true);
                        } else if ("done".equals(propertyName)) {
                            busyIconTimer.stop();
                            statusAnimationLabel.setIcon(idleIcon);
                            progressBar.setVisible(false);
                            progressBar.setValue(0);
                        } else if ("message".equals(propertyName)) {
                            String text = (String) (evt.getNewValue());
                            statusMessageLabel.setText((text == null) ? "" : text);
                            messageTimer.restart();
                        } else if ("progress".equals(propertyName)) {
                            int value = (Integer) (evt.getNewValue());
                            progressBar.setVisible(true);
                            progressBar.setIndeterminate(false);
                            progressBar.setValue(value);
                        } // end else if
                    } // end propertyChange()
                } // end new
                );
        TaskManagerApp.splashScreen.setStatus("Loading complete", 100);
        TaskManagerApp.splashScreen.hideSplash();
    } // end TaskManagerView()

    /**
     * .
     * @return icon image
     */
    public final Image getIcon() {
        return resourceMap.getImageIcon("Application.icon").getImage();
    } // end getIcon()

    /**
     * .
     */
    public final void bringFront() {
        this.getFrame().setVisible(true);

        int state = this.getFrame().getExtendedState();
        state &= ~JFrame.ICONIFIED;
        this.getFrame().setExtendedState(state);
        this.getFrame().setAlwaysOnTop(true);
        this.getFrame().toFront();
        this.getFrame().setAlwaysOnTop(false);
    } // end bringFront()

    public boolean isProjectListSynchOnce() {
        return projectListSynchOnce;
    }

    public void setProjectListSynchOnce(boolean projectListSynchOnce) {
        this.projectListSynchOnce = projectListSynchOnce;
    }

    /**
     * .
     */
    public final void changeApplicationIcon() {
        this.getFrame().setIconImage(this.getIcon());

        //this.getFrame().setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
    } // end changeApplicationIcon()

    /**
     * .
     */
    @Action
    public final void exitCommand() {
        this.parent.exit(null);
    } // end exitCommand()

    @Action
    public final void showSettings() {
        this.settingWindow.setVisible();
    }

    /**{@inherited}*/
    public void windowActivated(final WindowEvent e) {
        //come in focus
//        System.out.println("Active");
        if (this.getFrame().isAlwaysOnTop()) {
            this.getFrame().setAlwaysOnTop(false);
        }
    } // end windowActivated()

    /** {@inherited}*/
    public void windowClosed(final WindowEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
//        System.out.println("Closed");
    } // end windowClosed()

    /** {@inherited}*/
    public void windowClosing(final WindowEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
//        System.out.println("Closing");
    } // end windowClosing()

    /** {@inherited}*/
    public void windowDeactivated(final WindowEvent e) {
        //Go out of focus
//        System.out.println("Deactive");
    } // end windowDeactivated()

    /** {@inherited}.*/
    public void windowDeiconified(final WindowEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
//        System.out.println("DeIconified");
    } // end windowDeiconified()

    //implement method
    public void windowOpened(final WindowEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
//        System.out.println("Open");
    } // end windowOpened()

    /**{@inherited}*/
    public final void windowIconified(final WindowEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
//        System.out.println("Iconified " + this.getFrame().isAlwaysOnTop());
        if (SystemTray.isSupported() && !this.getFrame().isAlwaysOnTop()) {
            this.getFrame().setVisible(false);
            if (this.minimizeFirstTime == false) {
                trayIcon.displayMessage(
                        "",
                        resourceMap.getString("Application.name") + " is minimized in system tray.",
                        TrayIcon.MessageType.INFO);
            }
            this.minimizeFirstTime = true;
        } // end if
        if (this.getFrame().isAlwaysOnTop()) {
            this.getFrame().setExtendedState(JFrame.NORMAL);
            this.getFrame().setAlwaysOnTop(false);
        }
    } // end windowIconified()

    public final void setStatus(String text) {
        this.statusMessageLabel.setText(text);
        this.messageTimer.start();
    }

    private void makeWindowVisible() {
        this.getFrame().setVisible(true);
        if (!this.currentDate.equals(this.getDateCalendar().getTime())) {
            this.initCalendar();
        }
        int state = JFrame.NORMAL;
        this.getFrame().setExtendedState(state);
        this.getFrame().setAlwaysOnTop(true);
    }

    /**
     * .
     */
    public final void initTary() {
        if (SystemTray.isSupported()) {
            SystemTray tray = SystemTray.getSystemTray();
            Image image = this.resourceMap.getImageIcon("Application.tray.icon").getImage();


            MouseListener mouseListener = new MouseListener() {

                public void mouseClicked(final MouseEvent e) {
                    if (e.getButton() == MouseEvent.BUTTON1) {
                        TaskManagerView.this.makeWindowVisible();
                    }
                } // end mouseClicked()

                public void mouseEntered(final MouseEvent e) {
                } // end mouseEntered()

                public void mouseExited(final MouseEvent e) {
                } // end mouseExited()

                public void mousePressed(final MouseEvent e) {
                } // end mousePressed()

                public void mouseReleased(final MouseEvent e) {
                } // end mouseReleased()
            }; // end new

            ActionListener exitListener = new ActionListener() {

                public void actionPerformed(final ActionEvent e) {
                    exitCommand();
                } // end actionPerformed()
            }; // end new

            final PopupMenu popup = new PopupMenu();

            MenuItem exitMenuItem = new MenuItem("Exit");
            MenuItem showMenuItem = new MenuItem("Open");
            exitMenuItem.addActionListener(exitListener);
            showMenuItem.addActionListener(new ActionListener() {

                public void actionPerformed(ActionEvent e) {
                    TaskManagerView.this.makeWindowVisible();
                }
            });

            popup.add(exitMenuItem);
            popup.addSeparator();
            popup.add(showMenuItem);

            trayIcon = new TrayIcon(image, this.resourceMap.getString("Application.name"), popup);

            //this action will listen if click on the tray message box
            ActionListener actionListener = new ActionListener() {

                public void actionPerformed(final ActionEvent e) {
                } // end actionPerformed()
            }; // end new

            trayIcon.setImageAutoSize(true);
            trayIcon.addActionListener(actionListener);
            trayIcon.addMouseListener(mouseListener);
//            trayIcon.setImageAutoSize(true);

            try {
                tray.add(trayIcon);
            } catch (final AWTException e) {
                ChronicleLogger.getInstance().logDebug("TrayIcon could not be added.");
            } // end catch
        } else {
            ChronicleLogger.getInstance().logDebug("System Tray is not supported");
        } // end else
    } // end initTary()

    /**
     * Show a loading loading window with the given message
     * ensure that your other work has done in a thread.
     * @param message
     */
    public void showLoading(final String message, final Window window) {
        new Thread(new Runnable() {

            public void run() {
                if (loadingWindow == null) {
                    loadingWindow = new LoadingWindow(getFrame(), true);
                }
                loadingWindow.setMessage(message);
                ChronicleLogger.getInstance().logDebug("Window size: " + window.getWidth() + " " + window.getHeight());
                loadingWindow.setSize(window.getWidth(), window.getHeight());
                loadingWindow.setLocationRelativeTo(window);
                loadingWindow.setVisible(true);
            }
        }).start();
    }

    public void updateLoadingMessage(final String message) {
        if (loadingWindow != null) {
            SwingUtilities.invokeLater(new Runnable() {

                public void run() {
                    loadingWindow.setMessage(message);
                }
            });
        }
    }

    public void hideLoading() {
        if (loadingWindow != null && loadingWindow.isVisible()) {
            ChronicleLogger.getInstance().logDebug("Loading window hide");
            this.loadingWindow.dispose();
        }
    }

    /**
     * .
     */
    @Action
    public final void showAboutBox() {
        if (aboutBox == null) {
            JFrame mainFrame = TaskManagerApp.getApplication().getMainFrame();
            aboutBox = new TaskManagerAboutBox(mainFrame);
            aboutBox.setLocationRelativeTo(mainFrame);
        } // end if

        TaskManagerApp.getApplication().show(aboutBox);
    } // end showAboutBox()

    private void setHourTextBox(final String text) {
        this.hourTB.setText(text);
        this.hourTB.setForeground(Color.black);
    } // end setHourTextBox()

    //Todo - v1.1.0
    private void setMacro(int index) {
        if (this.checkValidity()) {
            if (index != -1) {
                if (JOptionPane.showConfirmDialog(this.timesheetTab, "There is a macro already set for this button,"
                        + "\nAre you sure you want to overwite it?",
                        "Confirm overwrite", JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION) {
                    return;
                }
            }
            int projectIndex = this.projectCB.getSelectedIndex() - 1;
            int activityIndex = this.activityCB.getSelectedIndex() - 1;
            Project project = this.user.getProjectAt(projectIndex);
            String projectId = project.getId();
            String activityId = project.getActivityAt(activityIndex).getId();

            DecimalFormat decimalFormat = new DecimalFormat("#.###");
            String strTime = this.hourTB.getText().trim();
            String decimalTime = decimalFormat.format(timeFormatter.formateToDecimal(strTime));
            String description = this.descriptionArea.getText().trim();

            PostData pdata = new PostData(
                    -1, //initially there is no local id
                    projectId,
                    project.getRate(),
                    activityId,
                    "",
                    description,
                    decimalTime,
                    (this.billAbleCB.getSelectedIndex() == 1) ? true : false);
            pdata.setProjectIndex(projectIndex);
            pdata.setActivityIndex(activityIndex);

            try {
                int localId = -1;
                if (index == -1) {
                    localId = this.dbManager.saveMacroData(pdata);
                    pdata.setLocalId(localId);
                } else {
                    pdata.setLocalId(this.macroData.getElementAt(index).getLocalId());
                    this.dbManager.updateMacroData(pdata);
                }
                this.setMacroData(index, pdata);
            } catch (SQLException ex) {
                ChronicleLogger.getInstance().logDebug("Couldn't save macro data at " + (index + 1));
            }
            setStatus("Successfully add or update the macro");
        } // end if
    } // end setMacro()

    
    private void setMacroData(int index, PostData pdata) {
        
        if (index == -1) {
            this.macroData.addPostData(pdata);
        } else {
            this.macroData.removeElementAt(index);
            this.macroData.addPostData(index, pdata);
        }

        this.setMacroButtonText(index, pdata.getDescription());
    }
    //todo -v1.1.0
    //example
//    private void macroButton1MouseClicked(java.awt.event.MouseEvent evt) {                                          
//        System.out.println("Mouse event: "+ evt.getModifiers());
//        if (evt.getButton() == evt.BUTTON1) {
//            this.addActivity(0);
//        } else if (evt.getButton() == evt.BUTTON3) {
//            this.setMacro(0);
//        }
//
//    }      
//
//
// example
//macroButton1.setText(resourceMap.getString("macroButton1.text")); // NOI18N
//        macroButton1.setToolTipText(resourceMap.getString("macroButton1.toolTipText")); // NOI18N
//        macroButton1.setName("macroButton1"); // NOI18N
//       macroButton1.addMouseListener(new java.awt.event.MouseAdapter() {
//            public void mouseClicked(java.awt.event.MouseEvent evt) {
//                macroButton1MouseClicked(evt, 0);
//            }
//
//            private void macroButton1MouseClicked(MouseEvent evt, int i) {
//                System.out.println("Here "+i);
//            }
//        });

    private void setMacroButtonText(int index, String description) {
//        this.macroButtons[index].setToolTipText(description);
//        if (description.length() > 7) {
//            description = description.substring(0, 5);
//        }
//        this.macroButtons[index].setText(description+"...");
    }

    private boolean addActivity(final int i) {
        if (this.macroData[i] != null) {
            SimpleDateFormat dateFromat = new SimpleDateFormat(globalDateFormat);
            String strDate = dateFromat.format(this.dateChooser.getDate());

            String decimalTime = this.getDecimalTimeAuto(this.macroData[i].getDecimalTime());
            int postLocalId = -1;
            try {
                postLocalId = this.dbManager.insertPostToDataBase("", this.macroData[i].getProjectId(),
                        this.macroData[i].getActivityId(), strDate, this.macroData[i].getDescription(),
                        decimalTime, (this.billAbleCB.getSelectedIndex() == 1) ? "true" : "false", 0);
            } catch (SQLException ex) {
                ChronicleLogger.getInstance().logCritical("Database error: " + ex.getMessage());
                JOptionPane.showMessageDialog(this.getFrame(), "Database error, Please try again.", "Error", JOptionPane.ERROR_MESSAGE);
                return false;
            }

            currentDatePostList.addPostData(
                    postLocalId,
                    this.macroData[i].getProjectId(),
                    this.macroData[i].getProjectRate(),
                    this.macroData[i].getActivityId(),
                    strDate,
                    this.macroData[i].getDescription(),
                    decimalTime,
                    this.macroData[i].isBillable()); //only date will be the selected date
            //remove total hour counter row
            this.activityTableModel.removeRow(this.activityTableModel.getRowCount() - 1);
            this.addToTable(
                    this.macroData[i].getProjectId(),
                    this.macroData[i].getActivityId(),
                    this.macroData[i].isBillable(),
                    this.macroData[i].getDescription(),
                    decimalTime, false);
            this.updateTableTotalHour(true);
            return true;
        } // end if
        return false;
    } // end addActivity()

    private String getDecimalTimeAuto(String strHour) {
        DecimalFormat decimalFormat = new DecimalFormat("#.###");
        double hour = timeFormatter.formateToDecimal(strHour);
        String decimalTime = decimalFormat.format(hour);
        if (decimalTime.equals("0")) {
            totalHour = 0.0;
            for (int i = 0; i < this.currentDatePostList.getSize(); i++) {
                totalHour += timeFormatter.formateToDecimal(this.currentDatePostList.getElementAt(i).getDecimalTime());
            }
            if (totalHour < 8.5) {
                decimalTime = decimalFormat.format(8.5 - totalHour);
            }
        }
        return decimalTime;
    }

    private boolean addActivity() {
        if (this.checkValidity()) {
            String decimalTime = this.getDecimalTimeAuto(this.hourTB.getText().trim());

            String strDescription = this.descriptionArea.getText().trim();
            int projectIndex = this.projectCB.getSelectedIndex() - 1;
            int activityIndex = this.activityCB.getSelectedIndex() - 1;

            Project project = this.user.getProjectAt(projectIndex);
            String projectId = project.getId();
            String activityId = project.getActivityAt(activityIndex).getId();

            SimpleDateFormat dateFromat = new SimpleDateFormat(globalDateFormat);
            String strDate = dateFromat.format(this.dateChooser.getDate());
            int postLocalId = -1;
            try {
                postLocalId = this.dbManager.insertPostToDataBase("", projectId, activityId, strDate, strDescription,
                        decimalTime, (this.billAbleCB.getSelectedIndex() == 1) ? "true" : "false", 0);
            } catch (SQLException ex) {
                ChronicleLogger.getInstance().logCritical("Database error: " + ex.getMessage());
                JOptionPane.showMessageDialog(this.getFrame(), "Database error, Please try again.", "Error", JOptionPane.ERROR_MESSAGE);
                return false;
            }
            //double timeValue = this.validTime(strHour);
            currentDatePostList.addPostData(postLocalId,
                    projectIndex, projectId, project.getRate(), activityIndex, activityId,
                    strDate,
                    strDescription,
                    decimalTime,
                    (this.billAbleCB.getSelectedIndex() == 1) ? true : false);
            //remove total hour counter row
            this.activityTableModel.removeRow(this.activityTableModel.getRowCount() - 1);
            this.addToTable(
                    projectId, activityId,
                    (this.billAbleCB.getSelectedIndex() == 1) ? true : false, strDescription, decimalTime, false);
            this.updateTableTotalHour(true);
            return true;
        } // end if

        return false;
    } // end addActivity()

    private void addToTable(final String projectId, final String activityId, final boolean billable,
            final String description, final String strHour, final boolean submitted) {

        Object[] rowData = new Object[this.activityTableModel.getColumnCount()];
        Project project = this.user.getProjectById(projectId);
        rowData[0] = project.getName();
        rowData[1] = project.getActivityById(activityId).getName();
        rowData[2] = description;
        rowData[3] = billable ? "Yes" : "No";
        rowData[4] = strHour;
        //rowData[5] = strDate;
        this.activityTableModel.insertRow(rowData);
        if (submitted) {
            this.activityTableModel.setRowEitible(this.activityTableModel.getRowCount() - 1, false);
        }
    } // end addToTable()

    private boolean checkValidity() {
        if (this.projectCB.getSelectedIndex() <= 0) {
            this.setStatus("Please select a Project");
            this.projectCB.grabFocus();

            return false;
        } // end if

        if (this.activityCB.getSelectedIndex() <= 0) {
            this.setStatus("Please select an Activity");
            this.activityCB.grabFocus();

            return false;
        } // end if

        String strDescription = this.descriptionArea.getText().trim();

        if (strDescription.equals("")) {
            this.setStatus("Please enter some descriptions.");
            this.descriptionArea.grabFocus();

            return false;
        } // end if

        String strHour = this.hourTB.getText().trim();
        double timeValue = timeFormatter.formateToDecimal(strHour);

        if (timeValue < 0.0) {
            this.setStatus("Please enter a valid time in Hour:Minute format");
            this.hourTB.grabFocus();

            return false;
        } // end if

        return true;
    } // end checkValidity()

    private void clearForm() {
        this.initHourTextBox();
        this.descriptionArea.setText("");
    } // end clearForm()

    private void initActivityTable() {
        this.activityTable = new JTable() {

            @Override
            public Component prepareRenderer(final TableCellRenderer renderer, final int row,
                    final int col) {
                Component comp = super.prepareRenderer(renderer, row, col);
                //even index, selected or not selected
                if (TaskManagerView.this.activityTable.getRowCount() - 1 == row) {
                    if (TaskManagerView.this.totalHour < 8.5) {
                        comp.setBackground(new Color(255, 150, 150));
                    } else {
                        comp.setBackground(new Color(150, 200, 255));
                    }
                } else if (((row % 2) == 0) && !isCellSelected(row, col)) {
                    if (!this.getModel().isCellEditable(row, 2)) {
                        comp.setBackground(Color.getHSBColor((float) 0, (float) 0, (float) 100.2));
                    } else {
                        comp.setBackground(Color.getHSBColor((float) 0, (float) 0, (float) 89.2));
                    } // end else
                } // end if
                else if (!isCellSelected(row, col)) {
                    if (!this.getModel().isCellEditable(row, 2)) {
                        comp.setBackground(Color.getHSBColor((float) 0, (float) 0, (float) 100.2));
                    } else {
                        comp.setBackground(Color.white);
                    } // end else
                } // end else if

                return comp;
            } // end prepareRenderer()
        }; // end new
        TaskManagerApp.splashScreen.setStatus("initializing activity table", 19);
        activityTableSP.setViewportView(this.activityTable);
        //table Model
        this.activityTableModel = new CustomTableModel(
                new String[]{"Project",
                    "Activity",
                    "Description",
                    "Billable",
                    "Hour"});
        this.activityTable.setModel(activityTableModel);

        // Disable auto resizing
        //this.activityTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        TableColumnModel tableColumnModel = this.activityTable.getColumnModel();
        tableColumnModel.getColumn(0).setPreferredWidth(100);
        tableColumnModel.getColumn(1).setPreferredWidth(100);
        tableColumnModel.getColumn(2).setPreferredWidth(150);

        tableColumnModel.getColumn(0).setMaxWidth(250);
        tableColumnModel.getColumn(1).setMaxWidth(250);
        tableColumnModel.getColumn(2).setMaxWidth(2000);
        tableColumnModel.getColumn(3).setMaxWidth(150);
        tableColumnModel.getColumn(4).setMaxWidth(80);

        TaskManagerApp.splashScreen.setStatus("initializing activity table", 20);

        this.updateTableTotalHour(true);

        TaskManagerApp.splashScreen.setStatus("initializing activity table", 21);

        this.tableMenu = new JPopupMenu();
        javax.swing.JMenuItem editRowMenu = new javax.swing.JMenuItem("Edit");
        editRowMenu.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                int index = TaskManagerView.this.activityTable.getSelectedRow();
                PostData pData = TaskManagerView.this.currentDatePostList.getElementAt(index);

                TaskManagerView.this.projectCB.setSelectedIndex(pData.getProjectIndex() + 1);
                TaskManagerView.this.activityCB.setSelectedIndex(pData.getActivityIndex() + 1);
                TaskManagerView.this.billAbleCB.setSelectedIndex(pData.isBillable() ? 1 : 2);
                TaskManagerView.this.setHourTextBox(pData.getDecimalTime());
                TaskManagerView.this.descriptionArea.setText(pData.getDescription());
                TaskManagerView.this.descriptionArea.grabFocus();
                try {
                    pData.setStatus(1);
                    TaskManagerView.this.dbManager.updatePostData(pData);
                } catch (SQLException ex) {
                    Logger.getLogger(TaskManagerView.class.getName()).log(Level.SEVERE, null, ex);
                }
                TaskManagerView.this.activityTableModel.removeRow(index);
                TaskManagerView.this.currentDatePostList.removeElementAt(index);
                TaskManagerView.this.updateTableTotalHour(false);
            }
        });
        javax.swing.JMenuItem deleteRowMenu = new javax.swing.JMenuItem("Delete");
        deleteRowMenu.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                int index = TaskManagerView.this.activityTable.getSelectedRow();
                PostData pData = TaskManagerView.this.currentDatePostList.getElementAt(index);
                try {
                    pData.setStatus(1);
                    TaskManagerView.this.dbManager.updatePostData(pData);
                } catch (SQLException ex) {
                    Logger.getLogger(TaskManagerView.class.getName()).log(Level.SEVERE, null, ex);
                }
                TaskManagerView.this.activityTableModel.removeRow(index);
                TaskManagerView.this.currentDatePostList.removeElementAt(index);
                TaskManagerView.this.updateTableTotalHour(false);
            }
        });
        this.tableMenu.add(editRowMenu);
        this.tableMenu.addSeparator();
        this.tableMenu.add(deleteRowMenu);
        TaskManagerApp.splashScreen.setStatus("initializing activity table", 22);
        //table event listener
        activityTable.addMouseListener(
                new java.awt.event.MouseAdapter() {

                    @Override
                    public void mouseClicked(final java.awt.event.MouseEvent evt) {
                        tableRowEditEvent(evt);
                    } // end mouseClicked()
                } // end new
                );
    } // end initActivityTable()

    //Override method
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        mainPanel = new javax.swing.JPanel();
        jTabbedPane1 = new javax.swing.JTabbedPane();
        timesheetTab = new javax.swing.JPanel();
        formPanel = new javax.swing.JPanel();
        hourTB = new javax.swing.JTextField();
        addActivityButton = new javax.swing.JButton();
        billAbleCB = new javax.swing.JComboBox();
        activityCB = new javax.swing.JComboBox();
        jScrollPane1 = new javax.swing.JScrollPane();
        descriptionArea = new javax.swing.JTextArea();
        calendarPanel = new javax.swing.JPanel();
        projectCB = new javax.swing.JComboBox();
        sideMacroBar = new javax.swing.JPanel();
        sideBarScrollPanel = new javax.swing.JScrollPane();
        activityTableSP = new javax.swing.JScrollPane();
        menuBar = new javax.swing.JMenuBar();
        javax.swing.JMenu fileMenu = new javax.swing.JMenu();
        jMenuItem2 = new javax.swing.JMenuItem();
        jMenuItem1 = new javax.swing.JMenuItem();
        javax.swing.JMenu helpMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem aboutMenuItem = new javax.swing.JMenuItem();
        statusPanel = new javax.swing.JPanel();
        javax.swing.JSeparator statusPanelSeparator = new javax.swing.JSeparator();
        statusMessageLabel = new javax.swing.JLabel();
        statusAnimationLabel = new javax.swing.JLabel();
        progressBar = new javax.swing.JProgressBar();
        jLabel2 = new javax.swing.JLabel();

        mainPanel.setMinimumSize(new java.awt.Dimension(300, 300));
        mainPanel.setName("mainPanel"); // NOI18N
        mainPanel.setPreferredSize(new java.awt.Dimension(550, 450));

        jTabbedPane1.setName("jTabbedPane1"); // NOI18N

        timesheetTab.setName("timesheetTab"); // NOI18N

        formPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        formPanel.setMinimumSize(new java.awt.Dimension(400, 90));
        formPanel.setName("formPanel"); // NOI18N

        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance().getContext().getResourceMap(TaskManagerView.class);
        hourTB.setForeground(resourceMap.getColor("hourTB.foreground")); // NOI18N
        hourTB.setText(resourceMap.getString("hourTB.text")); // NOI18N
        hourTB.setToolTipText(resourceMap.getString("hourTB.toolTipText")); // NOI18N
        hourTB.setMinimumSize(new java.awt.Dimension(27, 20));
        hourTB.setName("hourTB"); // NOI18N
        hourTB.setPreferredSize(new java.awt.Dimension(27, 20));
        hourTB.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                hourTBFocusGained(evt);
            }
            public void focusLost(java.awt.event.FocusEvent evt) {
                hourTBFocusLost(evt);
            }
        });

        addActivityButton.setText(resourceMap.getString("addActivityButton.text")); // NOI18N
        addActivityButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addActivityButtonActionPerformed(evt);
            }
        });

        billAbleCB.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Bill", "Yes", "No" }));
        billAbleCB.setName("billAbleCB"); // NOI18N

        activityCB.setBackground(resourceMap.getColor("activityCB.background")); // NOI18N
        activityCB.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Activity" }));
        activityCB.setMinimumSize(new java.awt.Dimension(55, 20));
        activityCB.setName("activityCB"); // NOI18N
        activityCB.setPreferredSize(new java.awt.Dimension(55, 20));
        activityCB.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                activityCBActionPerformed(evt);
            }
        });

        jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
        jScrollPane1.setName("jScrollPane1"); // NOI18N
        jScrollPane1.setPreferredSize(new java.awt.Dimension(166, 50));

        descriptionArea.setColumns(20);
        descriptionArea.setRows(5);
        descriptionArea.setName("descriptionArea"); // NOI18N
        jScrollPane1.setViewportView(descriptionArea);

        calendarPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        calendarPanel.setName("calendarPanel"); // NOI18N

        javax.swing.GroupLayout calendarPanelLayout = new javax.swing.GroupLayout(calendarPanel);
        calendarPanel.setLayout(calendarPanelLayout);
        calendarPanelLayout.setHorizontalGroup(
            calendarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 93, Short.MAX_VALUE)
        );
        calendarPanelLayout.setVerticalGroup(
            calendarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 20, Short.MAX_VALUE)
        );

        projectCB.setBackground(resourceMap.getColor("projectCB.background")); // NOI18N
        projectCB.setForeground(resourceMap.getColor("projectCB.foreground")); // NOI18N
        projectCB.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Project" }));
        projectCB.setMinimumSize(new java.awt.Dimension(54, 20));
        projectCB.setName("projectCB"); // NOI18N
        projectCB.setPreferredSize(new java.awt.Dimension(55, 20));
        projectCB.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                projectCBActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout formPanelLayout = new javax.swing.GroupLayout(formPanel);
        formPanel.setLayout(formPanelLayout);
        formPanelLayout.setHorizontalGroup(
            formPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, formPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(formPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(formPanelLayout.createSequentialGroup()
                        .addComponent(projectCB, 0, 140, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(activityCB, 0, 140, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(hourTB, javax.swing.GroupLayout.PREFERRED_SIZE, 33, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(billAbleCB, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(calendarPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(formPanelLayout.createSequentialGroup()
                        .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 428, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(addActivityButton, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        formPanelLayout.setVerticalGroup(
            formPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(formPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(formPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(formPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(projectCB, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addComponent(billAbleCB, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addComponent(hourTB, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addComponent(activityCB, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addComponent(calendarPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(formPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 56, Short.MAX_VALUE)
                    .addComponent(addActivityButton, javax.swing.GroupLayout.DEFAULT_SIZE, 56, Short.MAX_VALUE))
                .addContainerGap())
        );

        sideMacroBar.setName("sideMacroBar"); // NOI18N

        sideBarScrollPanel.setName("sideBarScrollPanel"); // NOI18N

        javax.swing.GroupLayout sideMacroBarLayout = new javax.swing.GroupLayout(sideMacroBar);
        sideMacroBar.setLayout(sideMacroBarLayout);
        sideMacroBarLayout.setHorizontalGroup(
            sideMacroBarLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(sideBarScrollPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 28, Short.MAX_VALUE)
        );
        sideMacroBarLayout.setVerticalGroup(
            sideMacroBarLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(sideBarScrollPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 408, Short.MAX_VALUE)
        );

        activityTableSP.setName("activityTableSP"); // NOI18N

        javax.swing.GroupLayout timesheetTabLayout = new javax.swing.GroupLayout(timesheetTab);
        timesheetTab.setLayout(timesheetTabLayout);
        timesheetTabLayout.setHorizontalGroup(
            timesheetTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(timesheetTabLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(timesheetTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(formPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(activityTableSP, javax.swing.GroupLayout.DEFAULT_SIZE, 516, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(sideMacroBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );
        timesheetTabLayout.setVerticalGroup(
            timesheetTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(timesheetTabLayout.createSequentialGroup()
                .addGap(14, 14, 14)
                .addGroup(timesheetTabLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(sideMacroBar, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(timesheetTabLayout.createSequentialGroup()
                        .addComponent(formPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(activityTableSP, javax.swing.GroupLayout.DEFAULT_SIZE, 290, Short.MAX_VALUE)))
                .addContainerGap())
        );

        jTabbedPane1.addTab(resourceMap.getString("timesheetTab.TabConstraints.tabTitle"), timesheetTab); // NOI18N

        javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
        mainPanel.setLayout(mainPanelLayout);
        mainPanelLayout.setHorizontalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jTabbedPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 575, Short.MAX_VALUE)
        );
        mainPanelLayout.setVerticalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jTabbedPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 458, Short.MAX_VALUE)
        );

        jTabbedPane1.getAccessibleContext().setAccessibleName(resourceMap.getString("jTabbedPane1.AccessibleContext.accessibleName")); // NOI18N

        menuBar.setName("menuBar"); // NOI18N

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance().getContext().getActionMap(TaskManagerView.class, this);
        fileMenu.setAction(actionMap.get("showSettings")); // NOI18N
        fileMenu.setText(resourceMap.getString("fileMenu.text")); // NOI18N
        fileMenu.setName("fileMenu"); // NOI18N

        jMenuItem2.setAction(actionMap.get("showSettings")); // NOI18N
        jMenuItem2.setText(resourceMap.getString("jMenuItem2.text")); // NOI18N
        jMenuItem2.setName("jMenuItem2"); // NOI18N
        fileMenu.add(jMenuItem2);

        jMenuItem1.setAction(actionMap.get("exitCommand")); // NOI18N
        jMenuItem1.setText(resourceMap.getString("jMenuItem1.text")); // NOI18N
        jMenuItem1.setName("jMenuItem1"); // NOI18N
        fileMenu.add(jMenuItem1);

        menuBar.add(fileMenu);

        helpMenu.setText(resourceMap.getString("helpMenu.text")); // NOI18N
        helpMenu.setName("helpMenu"); // NOI18N

        aboutMenuItem.setAction(actionMap.get("showAboutBox")); // NOI18N
        aboutMenuItem.setText(resourceMap.getString("aboutMenuItem.text")); // NOI18N
        aboutMenuItem.setName("aboutMenuItem"); // NOI18N
        helpMenu.add(aboutMenuItem);

        menuBar.add(helpMenu);

        statusPanel.setMinimumSize(new java.awt.Dimension(400, 200));
        statusPanel.setName("statusPanel"); // NOI18N

        statusPanelSeparator.setName("statusPanelSeparator"); // NOI18N

        statusMessageLabel.setName("statusMessageLabel"); // NOI18N

        statusAnimationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N

        progressBar.setName("progressBar"); // NOI18N

        javax.swing.GroupLayout statusPanelLayout = new javax.swing.GroupLayout(statusPanel);
        statusPanel.setLayout(statusPanelLayout);
        statusPanelLayout.setHorizontalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(statusPanelSeparator, javax.swing.GroupLayout.DEFAULT_SIZE, 575, Short.MAX_VALUE)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(statusMessageLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 405, Short.MAX_VALUE)
                .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(statusAnimationLabel)
                .addContainerGap())
        );
        statusPanelLayout.setVerticalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addComponent(statusPanelSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(statusMessageLabel)
                    .addComponent(statusAnimationLabel)
                    .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(3, 3, 3))
        );

        jLabel2.setText(resourceMap.getString("jLabel2.text")); // NOI18N
        jLabel2.setName("jLabel2"); // NOI18N

        setComponent(mainPanel);
        setMenuBar(menuBar);
        setStatusBar(statusPanel);
    }// </editor-fold>//GEN-END:initComponents

    private void addActivityButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addActivityButtonActionPerformed
        if (this.addActivity()) {
            this.clearForm();
        }
    }//GEN-LAST:event_addActivityButtonActionPerformed

    private void hourTBFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_hourTBFocusGained
        if (this.hourTB.getText().equals("H:M")) {
            this.setHourTextBox("");
        }
    }//GEN-LAST:event_hourTBFocusGained

    private void hourTBFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_hourTBFocusLost
        if (this.hourTB.getText().equals("")) {
            this.initHourTextBox();
        }
    }//GEN-LAST:event_hourTBFocusLost

    private void activityCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_activityCBActionPerformed
        if (this.activityCB.getSelectedIndex() > 0) {
            Project tmpPro = this.user.getProjectAt(this.projectCB.getSelectedIndex() - 1);
            if (tmpPro.getRate().equals("0")) {
                this.billAbleCB.setSelectedIndex(2);
            } else {
                this.billAbleCB.setSelectedIndex(1);
            }
        } else {
            this.billAbleCB.setSelectedIndex(0);
        }
    }//GEN-LAST:event_activityCBActionPerformed

    private void projectCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_projectCBActionPerformed
        if (this.projectCB.getSelectedIndex() > 0) {
            //get the project at selected index
            Project tmpPro = this.user.getProjectAt(this.projectCB.getSelectedIndex() - 1);
            this.activityCB.removeAllItems();
            this.activityCB.addItem("Activity");
            for (int i = 0; i < tmpPro.getActivityCount(); i++) {
                this.activityCB.addItem(tmpPro.getActivityAt(i).getName());
            }
        }
    }//GEN-LAST:event_projectCBActionPerformed

    /**
     * .
     */
    private void initHourTextBox() {
        this.hourTB.setText("H:M");
        this.hourTB.setForeground(Color.gray);
    } // end initHourTextBox()

    /**
     * .
     */
    public void initNotificationTimer() {
        int dely = 60 * 60 * 1000;//1hr
        if (this.user != null) {
            dely = this.user.getInterval() * 60 * 60 * 1000;
        }
        if (dely == 0) {
            if (notificationTimer != null) {
                notificationTimer.stop();
            }
            return;
        }
        if (notificationTimer != null) {
            notificationTimer.stop();
            notificationTimer.setDelay(dely);
            notificationTimer.start();
        } else {
            notificationTimer = new Timer(dely,
                    new ActionListener() {

                        public void actionPerformed(ActionEvent e) {
                            if (!getFrame().isActive()) {
                                ChronicleLogger.getInstance().logDebug("Show notification");
                                if (!notificationWindow.isVisible() && !notificationWindow.isActive()) {
                                    notificationWindow.showNotification();
                                } // end if
                            } // end if
                        }
                    });
            this.notificationTimer.start();
        }
    } // end intiNotification()

    private void initDataSynchronizationTimer() {
        int delay = 2 * 60 * 1000; //2min
        singleDaySynchronizationSkip = 0;
        if (this.dataSubmissionTimer == null) {
            this.dataSubmissionTimer = new java.util.Timer(true);
            TimerTask timerTask = new TimerTask() {

                PostDataList currentPostData = null;
                PostDataList newPostData = null;
                SimpleDateFormat dateFromat = new SimpleDateFormat(globalDateFormat);
                int[] taskStatus = {0, 1};

                @Override
                public void run() {
                    if (getFrame().isActive() && mouseActivityDetect == 1) {
                        ChronicleLogger.getInstance().logDebug(":( Data Synchronization delayed for user activity ):");
                        mouseActivityDetect = 0;
                        return;
                    }
                    String todayDate = dateFromat.format(dateChooser.getDate());
                    ChronicleLogger.getInstance().logDebug("***Going to start data synchronization process***");
                    System.gc();
                    if (toBeSubmittedPostList == null) {
                        toBeSubmittedPostList = new PostDataList();
                    }

                    if (toBeSubmittedPostList.isEmpty()) { //try to get unsbmitted posts
                        ChronicleLogger.getInstance().logDebug("No post to submit, trying to retreave from sqlite");
                        try {
                            toBeSubmittedPostList = dbManager.getPostDataListByStatus(taskStatus, 10);
                            ChronicleLogger.getInstance().logDebug("Post to submit found: " + toBeSubmittedPostList.getSize());
                        } catch (SQLException ex) {
                            ChronicleLogger.getInstance().logDebug("Sql error " + ex.getMessage());
                            setStatus("Got sql error while trying to get unsubmitted posts!");
                        }
                    }
                    if (!timeSheetClient.isLoggedIn()) {
                        int login = timeSheetClient.logIn();
                        if (login == 0) {
                            setStatus("Wrong user Id/Password, please update your user info");
                            ChronicleLogger.getInstance().logWarning("Couldn't login to the server, wrong user name or password");
                            return;
                        }
                        if (login == -1) {
                            ChronicleLogger.getInstance().logWarning("Couldn't login to the server, server is dead?");
                            return;
                        }

                    }
                    ChronicleLogger.getInstance().logDebug(":)Login ok. start data synchronization(:");
                    ParseSubmitPage parser = ParseSubmitPage.getInstance();
                    //If no left out local post to submit, lets do some synchronization
                    if (toBeSubmittedPostList.isEmpty() && timeSheetClient.isLoggedIn()) {
                        Calendar calendar = Calendar.getInstance(); //today
                        try {
                            int dayNO = calendar.get(Calendar.DATE);
                            int syncStartDay, syncEndDay;
                            if (calendar.getTimeInMillis() - user.getLastSyncTime() > 259200000) {//more than 3 days
                                ChronicleLogger.getInstance().logDebug("Will synchronize month");
                                syncStartDay = 1;
                                syncEndDay = dayNO;
                            } else {
                                if (singleDaySynchronizationSkip < 10) {
                                    singleDaySynchronizationSkip++;
                                    ChronicleLogger.getInstance().logDebug("Skiping single day synchronization " + singleDaySynchronizationSkip);
                                    return;
                                }
                                int index = randomIndex.nextInt(dayNO + 1);//incompleteDays.size();
                                if (index <= 0) {
                                    index = randomIndex.nextInt(dayNO + 1);
                                    if (index <= 0) {
                                        ChronicleLogger.getInstance().logDebug("Could not found any day to synchronization");
                                        return;
                                    }
                                }
                                ChronicleLogger.getInstance().logDebug("Day " + index + " of this month get selected for sync");
                                singleDaySynchronizationSkip = 0;
                                syncStartDay = index;
                                syncEndDay = index;
                            }
                            for (int i = syncStartDay; i <= syncEndDay; i++) {
                                calendar.set(Calendar.DATE, i);
                                String randomDay = dateFromat.format(calendar.getTime());

                                ChronicleLogger.getInstance().logDebug("Synchronizing with day: " + randomDay);
                                String currentPage = timeSheetClient.getSubmitPage(randomDay);
                                if (currentPage.equals("")) {
                                    timeSheetClient.setLoggedIn(false);
                                    ChronicleLogger.getInstance().logDebug("Could not get submit page, Will try later");
                                }
                                parser.setHtmlCode(currentPage, randomDay);
                                parser.parse(true, !isProjectListSynchOnce());
                                currentPostData = parser.getPostdataList();
                                ChronicleLogger.getInstance().logDebug("Found post count: " + currentPostData.getSize());
                                synchronizePostData(currentPostData, todayDate);
                                updateTotalPostHour(currentPostData);
                                if (!isProjectListSynchOnce() && user.replaceAllProject(parser.getProjects())) {
                                    loadProjectCombobox();
                                    setProjectListSynchOnce(true);
                                    ChronicleLogger.getInstance().logDebug("Project list got synchronized once");
                                }
                            }
                            //if we did not get any exception yet then sync was successful
                            if (syncStartDay == 1 && syncEndDay == dayNO) {
                                dbManager.updateLastSyncTime(calendar.getTimeInMillis());
                            }
                        } catch (IOException ex) {
                            ChronicleLogger.getInstance().logDebug("IOException: " + ex.getMessage());
                        } catch (SAXException ex) {
                            ChronicleLogger.getInstance().logDebug("Parseing error: " + ex.getMessage());
                        } catch (SQLException ex) {
                            ChronicleLogger.getInstance().logDebug("Couldn't retreave incomplete day list from DB");
                        }
                        return;
                    } else if (!toBeSubmittedPostList.isEmpty() && timeSheetClient.isLoggedIn()) {
                        ChronicleLogger.getInstance().logDebug("Going to sumbit post " + toBeSubmittedPostList.getSize());

                        //submit an item and get all post of that page and verify with current db
                        for (int i = 0; i < toBeSubmittedPostList.getSize(); i++) {
                            PostData pData = toBeSubmittedPostList.getElementAt(i);
                            try {
                                if (pData.getStatus() == 1) {
                                    ChronicleLogger.getInstance().logDebug("Update operation...");
                                    String pageSource = timeSheetClient.deletePost(pData.getStrDate(), pData.getServerId());
                                    if (pageSource.equals("") && !pData.getServerId().trim().equals("")) {

                                        pageSource = timeSheetClient.getSubmitPage(pData.getStrDate());
                                        if (pageSource.equals("")) {
                                            ChronicleLogger.getInstance().logDebug("Post delete failed, try later: " + pData.toString());
                                            return; //try later
                                        } else {
                                            parser.setHtmlCode(pageSource, pData.getStrDate());
                                            boolean pageOnsite = false;
                                            parser.parse(true, false);
                                            currentPostData = parser.getPostdataList();
                                            for (int j = 0; j < currentPostData.getSize(); j++) {
                                                if (currentPostData.getElementAt(j).getServerId().equals(pData.getServerId())) {
                                                    ChronicleLogger.getInstance().logDebug("Post delete failed, try later: " + pData.toString());
                                                    pageOnsite = true;
                                                    break;
                                                }
                                            }
                                            if (pageOnsite) {
                                                continue;
                                            }
                                            ChronicleLogger.getInstance().logDebug("Invalid post removed: " + pData.toString());
                                        }
                                    }
                                    dbManager.deletePostData(pData.getLocalId() + "");
                                    toBeSubmittedPostList.removeElementAt(i);
                                    i--;
                                } else if (pData.getStatus() == 0) {
                                    String currentPage = timeSheetClient.getSubmitPage(pData.getStrDate());
                                    if (currentPage.equals("")) {
                                        timeSheetClient.setLoggedIn(false);
                                        ChronicleLogger.getInstance().logDebug("Could not get submit page now. Will Try later.");
                                        continue;
                                    }
                                    parser.setHtmlCode(currentPage, pData.getStrDate());

                                    parser.parse(true, false);
                                    currentPostData = parser.getPostdataList();
                                    synchronizePostData(currentPostData, todayDate);
                                    //check if this data on the page is locally available
                                    newPostData = timeSheetClient.submitPost(pData);//submit the post to server

                                    if (newPostData != null && currentPostData.getSize() < newPostData.getSize()) {
                                        ChronicleLogger.getInstance().logDebug("Post Successfull, post count "
                                                + newPostData.getSize() + " On Date " + pData.getStrDate());
                                        boolean foundNewOne = false;

                                        //find the new post
                                        for (int j = 0; j < newPostData.getSize() && !foundNewOne; j++) {
                                            foundNewOne = true;
                                            for (int k = 0; k < currentPostData.getSize(); k++) {
                                                if (newPostData.getElementAt(j).getServerId().equals(
                                                        currentPostData.getElementAt(k).getServerId())) {
                                                    foundNewOne = false;
                                                    break;
                                                }
                                            }
                                            if (foundNewOne) {
                                                //update pData's serverid for local database
                                                pData.setServerId(newPostData.getElementAt(j).getServerId());
                                                pData.setStatus(2);
                                                dbManager.updatePostDataServerId(pData);
                                                break;
                                            }
                                        }
                                        //update color for the current date posts
                                        if (pData.getStrDate().equals(todayDate)) {
                                            //update current date view
                                            for (int j = 0; j < currentDatePostList.getSize(); j++) {
                                                if (currentDatePostList.getElementAt(j).getLocalId() == pData.getLocalId()) {
                                                    currentDatePostList.getElementAt(j).setStatus(2);
                                                    activityTableModel.setRowEitible(j, false);
                                                    activityTable.repaint();
                                                    break;
                                                }
                                            }

                                        }
                                        updateTotalPostHour(newPostData);
                                        toBeSubmittedPostList.removeElementAt(i);
                                        i--;
                                    }
                                } else {
                                    ChronicleLogger.getInstance().logCritical("Illigal project status "
                                            + "should be removed " + pData.toString() + "\nNot removing from local db");

                                    toBeSubmittedPostList.removeElementAt(i);
                                    i--;
                                }
                            } catch (IOException ex) {
                                ChronicleLogger.getInstance().logDebug("IOException " + ex.getMessage());
                                return;
                            } catch (SAXException ex) {
                                ChronicleLogger.getInstance().logDebug("Sax parser exception " + ex.getMessage());
                                return;
                            } catch (SQLException ex) {
                                ChronicleLogger.getInstance().logDebug("Database update error!"
                                        + " This post may get submitted again, which is a proble!");
                            }
                        }
                    } else {
                        ChronicleLogger.getInstance().logCritical("We should not come here");
                    }
                }
            };
            this.dataSubmissionTimer.schedule(timerTask, delay, delay); //start timer
            ChronicleLogger.getInstance().logDebug("Data submission timer started on " + delay + " milisec. interval");
        }
    }

    private void updateTotalPostHour(PostDataList singleDayPostData) throws SQLException {
        if (singleDayPostData.isEmpty()) {
            return;
        }
        String date = singleDayPostData.getElementAt(0).getStrDate();
        double totalDayHour = 0.0;
        for (int i = 0; i < singleDayPostData.getSize(); i++) {
            PostData tmpPostData = singleDayPostData.getElementAt(i);
            if (tmpPostData.getStrDate().equals(date)) {
                totalDayHour += Double.parseDouble(tmpPostData.getDecimalTime());
            }
        }
        dbManager.saveDayTotalHour(date, totalDayHour);
    }

    /**
     * All the post data should be of same day
     * 
     * @param newPostData
     * @param todayDate
     * @throws SQLException
     */
    private void synchronizePostData(PostDataList newPostData, String todayDate) throws SQLException {
        if (newPostData == null || newPostData.isEmpty()) {
            return;
        }
        String dayStr = newPostData.getElementAt(0).getStrDate();
        PostDataList daysPosts = dbManager.getPostDataListByDate(dayStr);

        for (int i = 0; i < daysPosts.getSize(); i++) {
            if (!daysPosts.getElementAt(i).getServerId().equals("")) {
                boolean deleted = true;
                for (int j = 0; j < newPostData.getSize(); j++) {
                    if (daysPosts.getElementAt(i).getServerId().equals(newPostData.getElementAt(j).getServerId())) {
                        deleted = false;
                        break;
                    }
                }
                if (deleted) {
                    ChronicleLogger.getInstance().logDebug("Deleted: " + daysPosts.getElementAt(i).toString());
                    dbManager.deletePostData(daysPosts.getElementAt(i).getLocalId() + "");
                }
            }
        }

        for (int i = 0; i < newPostData.getSize(); i++) {
            PostData tmpPostData = newPostData.getElementAt(i);
            boolean serverPost = true;
            for (int j = 0; j < daysPosts.getSize(); j++) {
                if (tmpPostData.getServerId().equals(daysPosts.getElementAt(j).getServerId())) {
                    serverPost = false;
                    break;
                }
            }
            if (serverPost) {
                dbManager.insertPostToDataBase(tmpPostData.getServerId(),
                        tmpPostData.getProjectId(), tmpPostData.getActivityId(),
                        tmpPostData.getStrDate(), tmpPostData.getDescription(),
                        tmpPostData.getDecimalTime(),
                        tmpPostData.isBillable() ? "True" : "False", 2);
            }
        }

        if (dayStr.equals(todayDate)) {
            this.updateTable(currentDate);
        }
    }

    /**
     * .
     */
    public void loadProjectCombobox() {
        this.projectCB.removeAllItems();
        this.projectCB.addItem("Project");
        for (int i = 0; i < this.user.getProjectCount(); i++) {
            this.projectCB.addItem(this.user.getProjectAt(i).getName());
        } // end for
    } // end loadProjectCombobox()

    /**
     * .
     * @param evt .
     */
    private void tableRowEditEvent(final MouseEvent evt) {
        int rowNum = this.activityTable.rowAtPoint(evt.getPoint());
        this.activityTable.getSelectionModel().setSelectionInterval(rowNum, rowNum);

        if (evt.getButton() == MouseEvent.BUTTON3 && this.activityTable.getSelectedRow() != -1
                && this.activityTable.getSelectedRow() != this.activityTable.getRowCount() - 1) {
            int x = evt.getXOnScreen() - this.getFrame().getLocationOnScreen().x;
            int y = evt.getYOnScreen() - this.getFrame().getLocationOnScreen().y;
            this.tableMenu.show(this.getFrame(), x, y);
        }
//        if (evt.getClickCount() == 2 && this.activityTable.getSelectedRow() != this.activityTable.getRowCount() - 1
//                && !this.currentDatePostList.getElementAt(this.activityTable.getSelectedRow()).isSubmitted()) {
//            int index = this.activityTable.getSelectedRow();
//
//            this.projectCB.setSelectedIndex(this.currentDatePostList.getElementAt(index).getProjectIndex() + 1);
//            this.activityCB.setSelectedIndex(this.currentDatePostList.getElementAt(index).getActivityIndex() + 1);
//            this.billAbleCB.setSelectedIndex(this.currentDatePostList.getElementAt(index).isBillable() ? 1 : 2);
//            this.setHourTextBox(this.currentDatePostList.getElementAt(index).getDecimalTime());
//            this.descriptionArea.setText(this.currentDatePostList.getElementAt(index).getDescription());
//            this.descriptionArea.grabFocus();
//
//            int localId = this.currentDatePostList.getElementAt(index).getLocalId();
//
//            this.activityTableModel.removeRow(index);
//            this.currentDatePostList.removeElementAt(index);
//            this.updateTableTotalHour(false);
//            try {
//                this.dbManager.deletePostData(localId + "");
//            } catch (SQLException ex) {
//                Logger.getLogger(TaskManagerView.class.getName()).log(Level.SEVERE, null, ex);
//            }
//        } // end if
    } // end tableRowEditEvent()

    /**
     * 
     * @param insertRow true if new row insertion is necessary (that is, if the last row is not already there then
     * set it true, if only update is needed then set it false)
     */
    private void updateTableTotalHour(boolean insertRow) {
        totalHour = 0.0;

        for (int i = 0; i < this.currentDatePostList.getSize(); i++) {
            totalHour += timeFormatter.formateToDecimal(this.currentDatePostList.getElementAt(i).getDecimalTime());
        } // end for
        if (insertRow) {
            Object[] rowData = new Object[this.activityTableModel.getColumnCount()];
            rowData[0] = "";
            rowData[1] = "";
            rowData[2] = "";
            rowData[3] = "Total Hour:";
            rowData[4] = new DecimalFormat("#.###").format(totalHour);
            //rowData[5] = strDate;
            this.activityTableModel.insertRow(rowData);
        } else {
            this.activityTableModel.setValueAt(new DecimalFormat("#.###").format(totalHour),
                    this.activityTableModel.getRowCount() - 1,
                    this.activityTableModel.getColumnCount() - 1);
        }
    } // end updateTotalHour()

    private void initTimesheetComponents() {
        this.currentDatePostList = new PostDataList();
        //init notification system
        this.notificationWindow = new NotificationWindow(this);
        this.getFrame().addWindowListener(this);
        TaskManagerApp.splashScreen.setStatus("Initialize Notification window", 15);

        this.changeApplicationIcon();
        this.initTary();
        TaskManagerApp.splashScreen.setStatus("Initialize tarry", 17);
        this.initActivityTable();
        TaskManagerApp.splashScreen.setStatus("load activity table", 23);

        this.dbManager = new DatabaseManager(this.dbFileName);
        TaskManagerApp.splashScreen.setStatus("Connecting to database", 25);

        try {
            this.dbManager.prepareConnection();
            this.dbManager.createTables();
        } catch (ClassNotFoundException ex) {
            TaskManagerApp.splashScreen.hideSplash();
            JOptionPane.showMessageDialog(this.getFrame(), "Database library not found",
                    "Database library missing", JOptionPane.WARNING_MESSAGE);
            System.exit(1);
        } catch (SQLException ex) {
            TaskManagerApp.splashScreen.hideSplash();
            JOptionPane.showMessageDialog(this.getFrame(), "Could not open or create database file,\n"
                    + "Please run this application from a location where file creation is allowed.",
                    "Database file missing", JOptionPane.WARNING_MESSAGE);
            ChronicleLogger.getInstance().logDebug("Sql error: " + ex.getMessage());
            System.exit(1);
        } catch (Exception ex) {
            TaskManagerApp.splashScreen.hideSplash();
            JOptionPane.showMessageDialog(this.getFrame(), "Could not open or create database file,\n"
                    + "Please run this application from a location where file creation is allowed.",
                    "Database file missing", JOptionPane.WARNING_MESSAGE);
            ChronicleLogger.getInstance().logDebug("Exception: " + ex.getMessage());
            System.exit(1);
        }
        //now initialize setting window
        TaskManagerApp.splashScreen.setStatus("Initializing user settings", 31);

        this.user = User.getInstance();
        this.settingWindow = new SettingWindow(this, true, this.user, this.dbManager);
        TaskManagerApp.splashScreen.setStatus("initializing user setting", 35);
        ArrayList<String> userInfo = this.dbManager.getUser();

        if (userInfo.isEmpty()) {
            TaskManagerApp.splashScreen.hideSplash();
            this.settingWindow.setVisible();
        } else {
            ChronicleLogger.getInstance().logDebug("User info found");
            this.user.setName(userInfo.get(1));
            this.user.setPassWord(userInfo.get(2));
            this.user.setUrl(userInfo.get(3));
            this.user.setPort(userInfo.get(4));
            this.user.setInterval(Integer.parseInt(userInfo.get(5)) % 13);
            this.user.setLastSyncTime(Long.parseLong(userInfo.get(6)));
            this.user.replaceAllProject(this.dbManager.getProjectAndActivity());
            this.settingWindow.setUser(this.user);
            this.loadProjectCombobox();
        }

        if (!this.user.getName().equals("")) {
            String title = this.appResourceMap.getString("Application.title");
            this.getFrame().setTitle(this.user.getName() + " - " + title);
        }

        TaskManagerApp.splashScreen.setStatus("initializing user setting", 40);
        this.initNotificationTimer();

        TaskManagerApp.splashScreen.setStatus("initializing user setting", 45);

        this.timeSheetClient = TimeSheetClient.getInstance();
        this.timeSheetClient.setUser(user);
        this.initDataSynchronizationTimer();
        TaskManagerApp.splashScreen.setStatus("initializing user setting.", 50);
        this.projectCB.setRenderer(new ToolTipComboBoxRendered());
        this.activityCB.setRenderer(new ToolTipComboBoxRendered());
        this.loadProjectCombobox();

        TaskManagerApp.splashScreen.setStatus("initializing macros..", 53);

        this.initializeMacro();


        TaskManagerApp.splashScreen.setStatus("initializing user setting..", 55);
        //Text box actions
        AbstractAction ctrlEnterAction = new AbstractAction("Ctrl+Enter Action") {

            public void actionPerformed(final ActionEvent e) {
                addActivity();
            } // end actionPerformed()
        }; // end new

        KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.CTRL_MASK);
        descriptionArea.getInputMap().put(key, ctrlEnterAction);
        TaskManagerApp.splashScreen.setStatus("Loading components...", 60);
        AbstractAction tabAction = new AbstractAction("Move Focus Forwards") {

            public void actionPerformed(final ActionEvent e) {
                ((JTextArea) e.getSource()).setText(((JTextArea) e.getSource()).getText().trim());
                ((Component) e.getSource()).transferFocus();
            } // end actionPerformed()
        }; // end new

        TaskManagerApp.splashScreen.setStatus("Loading components...", 63);

        descriptionArea.getInputMap().put(KeyStroke.getKeyStroke('\t'), tabAction);

        //calendar
        this.initCalendar();

        TaskManagerApp.splashScreen.setStatus("Loading components...", 73);
    }

    private void updateTable(Date currentDate) {
        this.currentDatePostList.clear();
        this.activityTableModel.removeAllRow();
        SimpleDateFormat dateFromat = new SimpleDateFormat(globalDateFormat);
        String strDate = dateFromat.format(currentDate);
        try {
            this.currentDatePostList = this.dbManager.getPostDataListByDate(strDate);
            for (int i = 0; i < this.currentDatePostList.getSize(); i++) {
                this.addToTable(currentDatePostList.getElementAt(i).getProjectId(),
                        currentDatePostList.getElementAt(i).getActivityId(),
                        currentDatePostList.getElementAt(i).isBillable(),
                        currentDatePostList.getElementAt(i).getDescription(),
                        currentDatePostList.getElementAt(i).getDecimalTime(),
                        currentDatePostList.getElementAt(i).isSubmitted());
            }
            this.updateTableTotalHour(true);
        } catch (SQLException ex) {
            ChronicleLogger.getInstance().logDebug(ex.getMessage());
        }
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JComboBox activityCB;
    private javax.swing.JScrollPane activityTableSP;
    private javax.swing.JButton addActivityButton;
    private javax.swing.JComboBox billAbleCB;
    private javax.swing.JPanel calendarPanel;
    private javax.swing.JTextArea descriptionArea;
    private javax.swing.JPanel formPanel;
    private javax.swing.JTextField hourTB;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JMenuItem jMenuItem1;
    private javax.swing.JMenuItem jMenuItem2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTabbedPane jTabbedPane1;
    private javax.swing.JPanel mainPanel;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JComboBox projectCB;
    private javax.swing.JScrollPane sideBarScrollPanel;
    private javax.swing.JPanel sideMacroBar;
    private javax.swing.JLabel statusAnimationLabel;
    private javax.swing.JLabel statusMessageLabel;
    private javax.swing.JPanel statusPanel;
    private javax.swing.JPanel timesheetTab;
    // End of variables declaration//GEN-END:variables
    private final Timer messageTimer;
    private final Timer busyIconTimer;
    private final Icon idleIcon;
    private final Icon[] busyIcons = new Icon[15];
    private int busyIconIndex = 0;
    private JDialog aboutBox;

    private void updateCalendarTextField(Calendar calendar) {
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        if (dayOfWeek == 6 || dayOfWeek == 7) {
            dateSpinner.setTextFieldBackGroundColor(new Color(220, 160, 250));
        } else {
            dateSpinner.setTextFieldBackGroundColor(Color.WHITE);
        }
    }

    private void initMouseListener() {
        MouseMotionListener mmListener = new MouseMotionListener() {

            public void mouseDragged(MouseEvent e) {
                mouseActivityDetect = 1;
            }

            public void mouseMoved(MouseEvent e) {
                mouseActivityDetect = 1;
            }
        };
        this.activityTable.addMouseMotionListener(mmListener);
        this.activityTableSP.addMouseMotionListener(mmListener);
        this.sideMacroBar.addMouseMotionListener(mmListener);
        this.formPanel.addMouseMotionListener(mmListener);
        this.getFrame().addMouseMotionListener(mmListener);
    }

    private void initCalendar() {
        Calendar tmpCal = this.getDateCalendar();
        this.currentDate = tmpCal.getTime();
        calendarPanel.setLayout(new GridBagLayout());
        this.dateSpinner = new JSpinnerDateEditor();
        JCalendar jCalendar = new JCalendar(this.currentDate);
        jCalendar.getDayChooser().setDbManager(dbManager);
        if (dateChooser != null) {
            this.dateChooser.cleanup();
        }
        dateChooser = new JDateChooser(jCalendar, this.currentDate, "dd/MM/yyyy", dateSpinner);

        this.updateCalendarTextField(tmpCal);
        this.updateTable(currentDate);
        calendarPanel.removeAll();
        calendarPanel.add(dateChooser);
        TaskManagerApp.splashScreen.setStatus("Loading components...", 70);

        dateChooser.addPropertyChangeListener(
                new java.beans.PropertyChangeListener() {

                    public void propertyChange(final PropertyChangeEvent evt) {
                        if (evt.getPropertyName().equals("date")) {
                            Date newDate = (Date) evt.getNewValue();

                            Calendar calendar = Calendar.getInstance();
                            calendar.setTime(newDate);
                            //we don't need hour/minute/second, so set them to zero
                            calendar.set(Calendar.HOUR, 0);
                            calendar.set(Calendar.MINUTE, 0);
                            calendar.set(Calendar.SECOND, 0);

                            if (currentDate.compareTo(calendar.getTime()) != 0) {
                                ChronicleLogger.getInstance().logDebug("Date Change " + currentDate + " to " + calendar.getTime());
                                updateCalendarTextField(calendar);
                                currentDate = calendar.getTime();
                                updateTable(currentDate);
                            }
                        } // end if
                    } // end propertyChange()
                } // end new
                );
        this.dateSpinner.addPropertyChangeListener(dateChooser);
    }

    private Calendar getDateCalendar() {
        Calendar tmpCal = Calendar.getInstance();
        //we don't need hour/minute/second, so set them to zero
        tmpCal.set(Calendar.HOUR, 0);
        tmpCal.set(Calendar.MINUTE, 0);
        tmpCal.set(Calendar.SECOND, 0);
        return tmpCal;
    }

    private void initializeMacro() {
        //this.sideBarScrollPanel = new JScrollPane();
//        this.sideMacroBar.add(this.sideBarScrollPanel);

        this.scrollablePanel = new ScrollablePanel(new GridLayout(0, 1));
        this.scrollablePanel.setScrollableHeight(ScrollablePanel.ScrollableSizeHint.FIT);
        this.scrollablePanel.setScrollableWidth(ScrollablePanel.ScrollableSizeHint.FIT);

        ScrollablePanel.IncrementType type = ScrollablePanel.IncrementType.PERCENT;
        this.scrollablePanel.setScrollableUnitIncrement(ScrollablePanel.VERTICAL, type, 10);
        this.scrollablePanel.setScrollableBlockIncrement(ScrollablePanel.VERTICAL, type, 100);
        this.scrollablePanel.setScrollableUnitIncrement(ScrollablePanel.HORIZONTAL, type, 10);
        this.scrollablePanel.setScrollableBlockIncrement(ScrollablePanel.HORIZONTAL, type, 100);

        macroAdder = new VerticalButton("+", true);
        macroAdder.setToolTipText("Add a new macro");
        macroAdder.setSize(23, 25);
        macroAdder.addMouseListener(new java.awt.event.MouseAdapter() {

            public void mouseClicked(java.awt.event.MouseEvent evt) {
                macroAdderMouseClicked(evt);
            }

            private void macroAdderMouseClicked(MouseEvent evt) {
                System.out.println("Here " + evt.getModifiers());
            }
        });
        System.out.println("Here");
        this.scrollablePanel.add(macroAdder);
        try {
            PostDataList macroDataList = this.dbManager.getMacroDataListe();
            for (int i = 0; i < 20; i++) {
                this.scrollablePanel.add(new VerticalButton("" + i, true));
            }
        } catch (SQLException ex) {
            ChronicleLogger.getInstance().logCritical("Macro data sql exception: " + ex.getMessage());
        }
        this.sideBarScrollPanel.setViewportView(this.scrollablePanel);
    }
}
